From: tsteven4 Date: Wed, 27 Feb 2019 14:25:14 +0000 (-0700) Subject: Object cleanup (#307) X-Git-Tag: archive/raspbian/1.10.0+ds-2+rpi1~1^2~12^2~8^2~36 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22%22/%22http:/www.example.com/cgi/%22https:/%22%22?a=commitdiff_plain;h=08610fc1107661009dc628a61a8d622d2143a2f5;p=gpsbabel.git Object cleanup (#307) * elminiate some early program exits. exits without cleanup make it harder to find memory leaks. fix a few leaks. enhance random format to support reading real time position data. correct some sign related warnings. * use invariant generator for random format. * make compilers happy with random. clang doesn't like: random.cc:61:42: note: read of non-constexpr variable 'generator' is not allowed in a constant expression constexpr double scalefactor = 1.0 / (*generator).max(); msvc doesn't like: warning C4100: 'fname': unreferenced formal parameter * catch main.cc up with master manually. --- diff --git a/defs.h b/defs.h index 8801e7566..19c3607bd 100644 --- a/defs.h +++ b/defs.h @@ -158,11 +158,11 @@ typedef enum { posndata } gpsdata_type; -#define NOTHINGMASK 0 -#define WPTDATAMASK 1 -#define TRKDATAMASK 2 -#define RTEDATAMASK 4 -#define POSNDATAMASK 8 +#define NOTHINGMASK 0U +#define WPTDATAMASK 1U +#define TRKDATAMASK 2U +#define RTEDATAMASK 4U +#define POSNDATAMASK 8U /* mask objective testing */ #define doing_nothing (global_opts.masked_objective == NOTHINGMASK) @@ -543,10 +543,7 @@ public: Waypoint(); ~Waypoint(); Waypoint(const Waypoint& other); - // the default assignment operator is not appropriate as we do deep copy of some members, - // and we haven't bothered to write an appropriate one. - // Catch attempts to use the default assignment operator. - Waypoint& operator=(const Waypoint& other) = delete; + Waypoint& operator=(const Waypoint& other); bool HasUrlLink() const; const UrlLink& GetUrlLink() const; @@ -870,29 +867,29 @@ void setshort_is_utf8(short_handle h, int is_utf8); /* REQUIRED means that the option is required to be set. * See also BEGIN/END_REQ */ -#define ARGTYPE_REQUIRED 0x40000000 +#define ARGTYPE_REQUIRED 0x40000000U /* HIDDEN means that the option does not appear in help texts. Useful * for debugging or testing options */ -#define ARGTYPE_HIDDEN 0x20000000 +#define ARGTYPE_HIDDEN 0x20000000U /* BEGIN/END_EXCL mark the beginning and end of an exclusive range of * options. No more than one of the options in the range may be selected * or set. If exactly one must be set, use with BEGIN/END_REQ * Both of these flags set is just like neither set, so avoid doing that. */ -#define ARGTYPE_BEGIN_EXCL 0x10000000 -#define ARGTYPE_END_EXCL 0x08000000 +#define ARGTYPE_BEGIN_EXCL 0x10000000U +#define ARGTYPE_END_EXCL 0x08000000U /* BEGIN/END_REQ mark the beginning and end of a required range of * options. One or more of the options in the range MUST be selected or set. * If exactly one must be set, use with BEGIN/END_EXCL * Both of these flags set is synonymous with REQUIRED, so use that instead * for "groups" of exactly one option. */ -#define ARGTYPE_BEGIN_REQ 0x04000000 -#define ARGTYPE_END_REQ 0x02000000 +#define ARGTYPE_BEGIN_REQ 0x04000000U +#define ARGTYPE_END_REQ 0x02000000U -#define ARGTYPE_TYPEMASK 0x00000fff -#define ARGTYPE_FLAGMASK 0xfffff000 +#define ARGTYPE_TYPEMASK 0x00000fffU +#define ARGTYPE_FLAGMASK 0xfffff000U #define ARG_NOMINMAX NULL, NULL #define ARG_TERMINATOR {0, 0, 0, 0, 0, ARG_NOMINMAX, NULL} @@ -986,7 +983,7 @@ void disp_vec(const char* vecname); void init_vecs(); void exit_vecs(); void disp_formats(int version); -const char* name_option(long type); +const char* name_option(uint32_t type); void printposn(double c, int is_lat); void* xcalloc(size_t nmemb, size_t size); diff --git a/main.cc b/main.cc index 2d86a4193..2ccf26e62 100644 --- a/main.cc +++ b/main.cc @@ -17,36 +17,48 @@ */ -#include -#include -#include -#include -#include - -#include "cet.h" -#include "cet_util.h" -#include "csv_util.h" -#include "defs.h" -#include "filterdefs.h" -#include "inifile.h" -#include "session.h" -#include "src/core/file.h" -#include "src/core/usasciicodec.h" -#include -#include -#include -#include -#include +#include // for setlocale, LC_NUMERIC, LC_TIME +#include // for signal, SIGINT, SIG_ERR +#include // for printf, fgetc, stdin +#include // for exit +#include // for strcmp +#include // for time + +#include // for QByteArray +#include // for QChar +#include // for QCoreApplication +#include // for QFile +#include // for QIODevice::ReadOnly +#include // for QLocale +#include // for QStack +#include // for QString +#include // for QStringList +#include // for QSysInfo +#include // for QTextCodec +#include // for QTextStream +#include // for QT_VERSION_STR +#include // for qPrintable, qVersion, QT_VERSION, QT_VERSION_CHECK + #ifdef AFL_INPUT_FUZZING #include "argv-fuzz-inl.h" #endif +#include "defs.h" +#include "cet_util.h" // for cet_convert_init, cet_convert_strings, cet_convert_deinit, cet_deregister, cet_register, cet_cs_vec_utf8 +#include "csv_util.h" // for csv_lineparse +#include "filter.h" // for Filter +#include "filterdefs.h" // for disp_filter_vec, disp_filter_vecs, disp_filters, exit_filter_vecs, find_filter_vec, free_filter_vec, init_filter_vecs +#include "inifile.h" // for inifile_done, inifile_init +#include "queue.h" // for queue +#include "session.h" // for start_session, session_exit, session_init +#include "src/core/datetime.h" // for DateTime +#include "src/core/file.h" // for File +#include "src/core/usasciicodec.h" // for UsAsciiCodec + #define MYNAME "main" // be careful not to advance argn passed the end of the list, i.e. ensure argn < qargs.size() #define FETCH_OPTARG qargs.at(argn).size() > 2 ? QString(qargs.at(argn)).remove(0,2) : qargs.size()>(argn+1) ? qargs.at(++argn) : QString() -void signal_handler(int sig); - class QargStackElement { public: @@ -194,12 +206,16 @@ print_extended_info() "\n"); } -int -main(int argc, char* argv[]) +static void +signal_handler(int sig) +{ + (void)sig; + tracking_status.request_terminate = 1; +} + +static int +run(const char* prog_name) { -#ifdef AFL_INPUT_FUZZING - AFL_INIT_ARGV(); -#endif int c; int argn; ff_vecs_t* ivecs = nullptr; @@ -211,87 +227,17 @@ main(int argc, char* argv[]) const char* ovec_opts = nullptr; const char* fvec_opts = nullptr; int opt_version = 0; - int did_something = 0; - const char* prog_name = argv[0]; /* argv is modified during processing */ + bool did_something = false; queue* wpt_head_bak, *rte_head_bak, *trk_head_bak; /* #ifdef UTF8_SUPPORT */ signed int wpt_ct_bak, rte_ct_bak, trk_ct_bak; /* #ifdef UTF8_SUPPORT */ - QStack qargs_stack = QStack(); + QStack qargs_stack; - // Create a QCoreApplication object to handle application initialization. - // In addition to being useful for argument decoding, the creation of a - // QCoreApplication object gets Qt initialized, especially locale related - // QTextCodec stuff. - // For example, this will get the QTextCodec::codecForLocale set - // correctly. - QCoreApplication app(argc, argv); // Use QCoreApplication::arguments() to process the command line. QStringList qargs = QCoreApplication::arguments(); - (void) new gpsbabel::UsAsciiCodec(); /* make sure a US-ASCII codec is available */ - -// MIN_QT_VERSION in configure.ac should correspond to the QT_VERSION_CHECK arguments in main.cc and gui/main.cc -#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) -#error This version of Qt is not supported. -#endif - - // The first invocation of QTextCodec::codecForLocale() may result in LC_ALL being set to the native environment - // as opposed to the initial default "C" locale. - // This was demonstrated with Qt5 on Mac OS X. - // TODO: This need to invoke QTextCodec::codecForLocale() may be taken care of - // by creating a QCoreApplication. -#ifdef DEBUG_LOCALE - printf("Initial locale: %s\n",setlocale(LC_ALL, NULL)); -#endif - (void) QTextCodec::codecForLocale(); -#ifdef DEBUG_LOCALE - printf("Locale after codedForLocale: %s\n",setlocale(LC_ALL, NULL)); -#endif - // As recommended in QCoreApplication reset the locale to the default. - // Note the documentation says to set LC_NUMERIC, but QCoreApplicationPrivate::initLocale() - // actually sets LC_ALL. - // Perhaps we should restore LC_ALL instead of only LC_NUMERIC. - if (strcmp(setlocale(LC_NUMERIC,nullptr), "C") != 0) { -#ifdef DEBUG_LOCALE - printf("Resetting LC_NUMERIC\n"); -#endif - setlocale(LC_NUMERIC,"C"); -#ifdef DEBUG_LOCALE - printf("LC_ALL: %s\n",setlocale(LC_ALL, NULL)); -#endif - } - /* reset LC_TIME for strftime */ - if (strcmp(setlocale(LC_TIME,nullptr), "C") != 0) { -#ifdef DEBUG_LOCALE - printf("Resetting LC_TIME\n"); -#endif - setlocale(LC_TIME,"C"); -#ifdef DEBUG_LOCALE - printf("LC_ALL: %s\n",setlocale(LC_ALL, NULL)); -#endif - } - - global_opts.objective = wptdata; - global_opts.masked_objective = NOTHINGMASK; /* this makes the default mask behaviour slightly different */ - global_opts.charset_name.clear(); - global_opts.inifile = nullptr; - - gpsbabel_now = time(nullptr); /* gpsbabel startup-time */ - gpsbabel_time = current_time().toTime_t(); /* same like gpsbabel_now, but freezed to zero during testo */ - - if (gpsbabel_time != 0) { /* within testo ? */ - global_opts.inifile = inifile_init(QString(), MYNAME); - } - - init_vecs(); - init_filter_vecs(); - cet_register(); - session_init(); - waypt_init(); - route_init(); - if (qargs.size() < 2) { usage(prog_name,1); - exit(0); + return 0; } /* @@ -315,7 +261,7 @@ main(int argc, char* argv[]) if (qargs.at(argn).size() > 2 && qargs.at(argn).at(2).toLatin1() == 'V') { print_extended_info(); } - exit(0); + return 0; } if (qargs.at(argn).size() > 1 && (qargs.at(argn).at(1).toLatin1() == '?' || qargs.at(argn).at(1).toLatin1() == 'h')) { @@ -324,7 +270,7 @@ main(int argc, char* argv[]) } else { usage(prog_name,0); } - exit(0); + return 0; } c = qargs.at(argn).size() > 1 ? qargs.at(argn).at(1).toLatin1() : '\0'; @@ -364,7 +310,7 @@ main(int argc, char* argv[]) fatal("Format does not support reading.\n"); } if (global_opts.masked_objective & POSNDATAMASK) { - did_something = 1; + did_something = true; break; } /* simulates the default behaviour of waypoints */ @@ -382,7 +328,7 @@ main(int argc, char* argv[]) cet_convert_strings(global_opts.charset, nullptr, nullptr); cet_convert_deinit(); - did_something = 1; + did_something = true; break; case 'F': optarg = FETCH_OPTARG; @@ -537,14 +483,14 @@ main(int argc, char* argv[]) */ case '^': disp_formats(opt_version); - exit(0); + return 0; case '%': disp_filters(opt_version); - exit(0); + return 0; case 'h': case '?': usage(prog_name,0); - exit(0); + return 0; case 'p': optarg = FETCH_OPTARG; inifile_done(global_opts.inifile); @@ -590,7 +536,7 @@ main(int argc, char* argv[]) if (qargs.size() > 2) { fatal("Extra arguments on command line\n"); } else if ((!qargs.isEmpty()) && ivecs) { - did_something = 1; + did_something = true; /* simulates the default behaviour of waypoints */ if (doing_nothing) { global_opts.masked_objective |= WPTDATAMASK; @@ -625,7 +571,7 @@ main(int argc, char* argv[]) } } else if (!qargs.isEmpty()) { usage(prog_name,0); - exit(0); + return 0; } if (ovecs == nullptr) { /* @@ -710,7 +656,7 @@ main(int argc, char* argv[]) if (ovecs && ovecs->position_ops.wr_deinit) { ovecs->position_ops.wr_deinit(); } - exit(0); + return 0; } @@ -718,6 +664,90 @@ main(int argc, char* argv[]) fatal("Nothing to do! Use '%s -h' for command-line options.\n", prog_name); } + return 0; +} + +int +main(int argc, char* argv[]) +{ +#ifdef AFL_INPUT_FUZZING + AFL_INIT_ARGV(); +#endif + int rc = 0; + const char* prog_name = argv[0]; /* may not match QCoreApplication::arguments().at(0)! */ + +// MIN_QT_VERSION in configure.ac should correspond to the QT_VERSION_CHECK arguments in main.cc and gui/main.cc +#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) +#error This version of Qt is not supported. +#endif + +#ifdef DEBUG_LOCALE + printf("Initial locale: %s\n",setlocale(LC_ALL, NULL)); +#endif + + // Create a QCoreApplication object to handle application initialization. + // In addition to being useful for argument decoding, the creation of a + // QCoreApplication object gets Qt initialized, especially locale related + // QTextCodec stuff. + // For example, this will get the QTextCodec::codecForLocale set + // correctly. + QCoreApplication app(argc, argv); + + // The first invocation of QTextCodec::codecForLocale() or + // construction of QCoreApplication object + // may result in LC_ALL being set to the native environment + // as opposed to the initial default "C" locale. + // This was demonstrated with Qt5 on Mac OS X. +#ifdef DEBUG_LOCALE + printf("Locale after initial setup: %s\n",setlocale(LC_ALL, NULL)); +#endif + // As recommended in QCoreApplication reset the locale to the default. + // Note the documentation says to set LC_NUMERIC, but QCoreApplicationPrivate::initLocale() + // actually sets LC_ALL. + // Perhaps we should restore LC_ALL instead of only LC_NUMERIC. + if (strcmp(setlocale(LC_NUMERIC,nullptr), "C") != 0) { +#ifdef DEBUG_LOCALE + printf("Resetting LC_NUMERIC\n"); +#endif + setlocale(LC_NUMERIC,"C"); +#ifdef DEBUG_LOCALE + printf("LC_ALL: %s\n",setlocale(LC_ALL, NULL)); +#endif + } + /* reset LC_TIME for strftime */ + if (strcmp(setlocale(LC_TIME,nullptr), "C") != 0) { +#ifdef DEBUG_LOCALE + printf("Resetting LC_TIME\n"); +#endif + setlocale(LC_TIME,"C"); +#ifdef DEBUG_LOCALE + printf("LC_ALL: %s\n",setlocale(LC_ALL, NULL)); +#endif + } + + (void) new gpsbabel::UsAsciiCodec(); /* make sure a US-ASCII codec is available */ + + global_opts.objective = wptdata; + global_opts.masked_objective = NOTHINGMASK; /* this makes the default mask behaviour slightly different */ + global_opts.charset_name.clear(); + global_opts.inifile = nullptr; + + gpsbabel_now = time(nullptr); /* gpsbabel startup-time */ + gpsbabel_time = current_time().toTime_t(); /* same like gpsbabel_now, but freezed to zero during testo */ + + if (gpsbabel_time != 0) { /* within testo ? */ + global_opts.inifile = inifile_init(QString(), MYNAME); + } + + init_vecs(); + init_filter_vecs(); + cet_register(); + session_init(); + waypt_init(); + route_init(); + + rc = run(prog_name); + cet_deregister(); waypt_flush_all(); route_flush_all(); @@ -726,11 +756,5 @@ main(int argc, char* argv[]) exit_filter_vecs(); inifile_done(global_opts.inifile); - exit(0); -} - -void signal_handler(int sig) -{ - (void)sig; - tracking_status.request_terminate = 1; + exit(rc); } diff --git a/nmn4.cc b/nmn4.cc index 476f9d719..13237a58d 100644 --- a/nmn4.cc +++ b/nmn4.cc @@ -90,7 +90,7 @@ nmn4_read_data() int column = -1; QString c = csv_lineparse(str, "|", "", column++); - while (c != nullptr) { + while (!c.isNull()) { switch (column) { case 0: /* "-" */ /* unknown fields for the moment */ case 1: /* "-" */ diff --git a/pocketfms_wp.cc b/pocketfms_wp.cc index 603c4820d..dcaeea49f 100644 --- a/pocketfms_wp.cc +++ b/pocketfms_wp.cc @@ -84,6 +84,9 @@ data_read() } wpt->longitude = wppos_to_dec(s); waypt_add(wpt); + + // continue reading until csv_lineparse returns null indicating all dynamic memory has been deallocated. + while (csv_lineparse(nullptr, "\\w", "", linecount)); } } diff --git a/random.cc b/random.cc index dcfe680cb..303dfd569 100644 --- a/random.cc +++ b/random.cc @@ -18,15 +18,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ +#include // for atoi +#include // for mt19937 + +#include // for QDateTime +#include // for QString +#include // for QThread + #include "defs.h" -#include "garmin_fs.h" -#include "jeeps/gpsmath.h" -#include -#include +#include "garmin_fs.h" // for garmin_fs_t, GMSD_SET, garmin_fs_flags_t, garmin_fs_alloc #define MYNAME "random" -static char* opt_points, *opt_seed; +static char* opt_points, *opt_seed, *opt_nodelay; static arglist_t random_args[] = { { @@ -37,20 +41,47 @@ static arglist_t random_args[] = { "seed", &opt_seed, "Starting seed of the internal number generator", nullptr, ARGTYPE_INT, "1", nullptr, nullptr }, + { + "nodelay", &opt_nodelay, "Output realtime points without delay", nullptr, + ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, ARG_TERMINATOR }; +// this generator is invariant across platforms. +static std::mt19937* generator; + +// we do this cheesy distribution function because we need it to be invariant across platforms. +// note uniform_int_distribution is not invariant. +template +static T +rand_num(const T max) +{ + T retval; + // scalefactor expression assumes generator is mt19937. + constexpr double scalefactor = 1.0 / std::mt19937::max(); + do { + retval = static_cast(static_cast(max) * scalefactor * (*generator)()); + } while (retval >= max); + return retval; +} static double rand_dbl(const double max) { - return max * rand() / (((double)RAND_MAX) + 1); + return rand_num(max); +} + +static float +rand_flt(const float max) +{ + return rand_num(max); } static int rand_int(const int max) { - return (int)((double)max * rand() / (((double)RAND_MAX) + 1)); + return rand_num(max); } /* rand_str always returns a valid string with len >= 0 */ @@ -60,7 +91,7 @@ rand_str(const int maxlen, const char* fmt) { int len = rand_int(maxlen) + 1; - char* res = (char*) xmalloc(len + 1); + auto res = (char*) xmalloc(len + 1); res[len] = '\0'; for (int i = 0; i < len; i++) { @@ -96,49 +127,26 @@ rand_qstr(const int maxlen, const char* fmt) static void random_rd_init(const QString&) { + generator = new std::mt19937; + if (opt_seed) { + generator->seed(atoi(opt_seed)); + } else { + generator->seed(gpsbabel_now); + } } static void random_rd_deinit() { + delete generator; } -static void -random_read() -{ #define RND(a) (rand_int(a) > 0) - route_head* head; - Waypoint* prev = nullptr; - time_t time = gpsbabel_time; - - if (opt_seed) { - srand(atoi(opt_seed)); - } else { - srand(gpsbabel_now); - } - - - int points = (opt_points) ? atoi(opt_points) : rand_int(128) + 1; - if (doing_trks || doing_rtes) { - head = route_head_alloc(); - if (doing_trks) { - head->rte_name = rand_qstr(8, "Trk_%s"); - track_add_head(head); - } else { - head->rte_name = rand_qstr(8, "Rte_%s"); - route_add_head(head); - } - head->rte_desc = rand_qstr(16, nullptr); - if RND(3) { - head->rte_urls.AddUrlLink(UrlLink(rand_qstr(8, "http://rteurl.example.com/%s"))); - } - } else { - head = nullptr; - } - - for (int i = 0; i < points; i++) { - Waypoint* wpt = new Waypoint; +static Waypoint* +random_generate_wpt(int i, const QDateTime& time, const Waypoint* prev) +{ + auto wpt = new Waypoint; garmin_fs_t* gmsd = garmin_fs_alloc(-1); fs_chain_add(&wpt->fs, (format_specific_data*) gmsd); @@ -146,22 +154,22 @@ random_read() wpt->shortname = rand_qstr(8, "Wpt_%s"); } while (wpt->shortname == nullptr); - wpt->latitude = rand_dbl(180) - 90; - wpt->longitude = rand_dbl(360) - 180; + wpt->latitude = rand_dbl(180.0) - 90.0; + wpt->longitude = rand_dbl(360.0) - 180.0; /* !!! "if RND(3) ..." produces some leaks in generated data !!! */ if RND(3) { - wpt->altitude = rand_int(1000) / 10; + wpt->altitude = rand_dbl(100.0); } if RND(3) { - WAYPT_SET(wpt, temperature, rand_int(320) / 10.0); + WAYPT_SET(wpt, temperature, rand_flt(32.0f)); } if RND(3) { - WAYPT_SET(wpt, proximity, rand_int(10000) / 10.0); + WAYPT_SET(wpt, proximity, rand_dbl(1000.0)); } if RND(3) { - WAYPT_SET(wpt, depth, rand_int(10000) / 10.0); + WAYPT_SET(wpt, depth, rand_dbl(1000.0)); } if RND(3) { wpt->AddUrlLink(rand_qstr(8, "http://link1.example.com/%s")); @@ -174,22 +182,18 @@ random_read() } wpt->SetCreationTime(time); - if RND(3) { - wpt->creation_time = wpt->creation_time.addMSecs(rand_int(1000)); - } - time += rand_int(10) + 1; - if (doing_trks) { + if (doing_trks || doing_posn) { if (i > 0) { - wpt->latitude = prev->latitude + (rand_dbl(1) / 1000); - wpt->longitude = prev->longitude + (rand_dbl(1) / 1000); + wpt->latitude = prev->latitude + rand_dbl(0.001); + wpt->longitude = prev->longitude + rand_dbl(0.001); WAYPT_SET(wpt, course, waypt_course(prev, wpt)); WAYPT_SET(wpt, speed, waypt_speed(prev, wpt)); } wpt->sat = rand_int(12 + 1); - wpt->hdop = (rand_int(500)) / 10.0; - wpt->vdop = (rand_int(500)) / 10.0; - wpt->pdop = (rand_int(500)) / 10.0; + wpt->hdop = rand_flt(50.0f); + wpt->vdop = rand_flt(50.0f); + wpt->pdop = rand_flt(50.0f); wpt->fix = (fix_type)(rand_int(6) - 1); if RND(3) { wpt->cadence = rand_int(255); @@ -199,8 +203,8 @@ random_read() } } else { if (doing_rtes && (i > 0)) { - wpt->latitude = prev->latitude + (rand_dbl(1) / 100); - wpt->longitude = prev->longitude + (rand_dbl(1) / 100); + wpt->latitude = prev->latitude + rand_dbl(0.01); + wpt->longitude = prev->longitude + rand_dbl(0.01); } if RND(3) { wpt->description = rand_qstr(16, "Des_%s"); @@ -231,6 +235,37 @@ random_read() } } + return wpt; +} + +static void +random_read() +{ + + route_head* head; + Waypoint* prev = nullptr; + QDateTime time = QDateTime::fromTime_t(gpsbabel_time); + + int points = (opt_points) ? atoi(opt_points) : rand_int(128) + 1; + if (doing_trks || doing_rtes) { + head = route_head_alloc(); + if (doing_trks) { + head->rte_name = rand_qstr(8, "Trk_%s"); + track_add_head(head); + } else { + head->rte_name = rand_qstr(8, "Rte_%s"); + route_add_head(head); + } + head->rte_desc = rand_qstr(16, nullptr); + if RND(3) { + head->rte_urls.AddUrlLink(UrlLink(rand_qstr(8, "http://rteurl.example.com/%s"))); + } + } else { + head = nullptr; + } + + for (int i = 0; i < points; i++) { + Waypoint* wpt = random_generate_wpt(i, time, prev); if (doing_trks) { track_add_wpt(head, wpt); } else if (doing_rtes) { @@ -239,10 +274,65 @@ random_read() waypt_add(wpt); } + time = time.addMSecs(1000 + rand_int(10000)); prev = wpt; } } +struct realtime_data { + QDateTime time; + int points{-1}; + int point_count{0}; + Waypoint prev; +}; +static realtime_data* realtime; + +void +random_rd_posn_init(const QString&) +{ + generator = new std::mt19937; + if (opt_seed) { + generator->seed(atoi(opt_seed)); + } else { + generator->seed(gpsbabel_now); + } + realtime = new realtime_data; + if (opt_points) { + realtime->points = atoi(opt_points); + } + realtime->time = QDateTime::fromTime_t(gpsbabel_time); +} + +void +random_rd_posn_deinit() +{ + delete generator; + delete realtime; +} + +static Waypoint* +random_rd_posn(posn_status* p_status) +{ + Waypoint* wpt = random_generate_wpt(realtime->point_count, realtime->time, &(realtime->prev)); + + if (p_status && (realtime->points > 0) && (realtime->point_count >= realtime->points)) { + p_status->request_terminate = 1; + } + ++realtime->point_count; + + int delta_msecs= 1000 + rand_int(1000); + realtime->time = realtime->time.addMSecs(delta_msecs); + if (!opt_nodelay) { + QThread::msleep(delta_msecs); + } + + // copy the waypoint as main will delete the returned waypt + // after write and we need it to generate the next wpt to + // simulate realtime tracking data. + realtime->prev = *wpt; + + return wpt; +} ff_vecs_t random_vecs = { ff_type_internal, @@ -259,7 +349,10 @@ ff_vecs_t random_vecs = { nullptr, /* write */ nullptr, /* exit */ random_args, - CET_CHARSET_ASCII, 1 /* fixed */ - , NULL_POS_OPS, + CET_CHARSET_ASCII, 1, /* fixed */ + { + random_rd_posn_init, random_rd_posn, random_rd_posn_deinit, + nullptr, nullptr, nullptr, + }, nullptr }; diff --git a/reference/realtime.csv b/reference/realtime.csv new file mode 100644 index 000000000..07a651856 --- /dev/null +++ b/reference/realtime.csv @@ -0,0 +1,10 @@ +-28.606309,41.491196,85.918,Wpt_RD,1970-01-01T00:00:00Z +-28.605513,41.492136,,Wpt_lBahVv7,1970-01-01T00:00:01.745Z +-28.604906,41.492637,31.126,Wpt_hTE,1970-01-01T00:00:03.253Z +-28.604548,41.493038,,Wpt_0H,1970-01-01T00:00:04.655Z +-28.604396,41.493069,24.212,Wpt_k,1970-01-01T00:00:06.328Z +-28.603524,41.493167,5.795,Wpt_iX,1970-01-01T00:00:07.835Z +-28.603490,41.494039,36.201,Wpt_TyhlOke,1970-01-01T00:00:09.090Z +-28.602885,41.494402,73.608,Wpt_rS,1970-01-01T00:00:10.507Z +-28.602833,41.494822,2.947,Wpt_obZdF3b0,1970-01-01T00:00:11.965Z +-28.601890,41.495138,,ESTIMATED Position,1970-01-01T00:00:13.543Z diff --git a/testo.d/realtime.test b/testo.d/realtime.test new file mode 100644 index 000000000..a5587e344 --- /dev/null +++ b/testo.d/realtime.test @@ -0,0 +1,15 @@ + +echo 'DESCRIPTION realtime tracking 1' >>${TMPDIR}/realtime1.style +echo 'EXTENSION csv' >>${TMPDIR}/realtime1.style +echo 'FIELD_DELIMITER COMMA' >>${TMPDIR}/realtime1.style +echo 'RECORD_DELIMITER NEWLINE' >>${TMPDIR}/realtime1.style +echo 'IFIELD LON_DECIMAL,"","%f"' >>${TMPDIR}/realtime1.style +echo 'IFIELD LAT_DECIMAL,"","%f"' >>${TMPDIR}/realtime1.style +echo 'IFIELD ALT_METERS,"","%.3f"' >>${TMPDIR}/realtime1.style +echo 'IFIELD SHORTNAME,"","%s"' >>${TMPDIR}/realtime1.style +echo 'IFIELD ISO_TIME_MS,"","%s"' >>${TMPDIR}/realtime1.style +# test real time tracking +gpsbabel -T -i random,points=10,seed=22,nodelay -f dummy -o xcsv,style=${TMPDIR}/realtime1.style -F ${TMPDIR}/realtime.csv +compare ${REFERENCE}/realtime.csv ${TMPDIR}/realtime.csv + + diff --git a/tpo.cc b/tpo.cc index 16a11d5b0..2cff68ee3 100644 --- a/tpo.cc +++ b/tpo.cc @@ -747,13 +747,11 @@ static void tpo_process_tracks() if (buf[jj] == 0) { - printf("Found unexpected ZERO\n"); - exit(1); + fatal(MYNAME ": Found unexpected ZERO\n"); } if (latscale == 0 || lonscale == 0) { - printf("Found bad scales lonscale=0x%x latscale=0x%x\n", lonscale, latscale); - exit(1); + fatal(MYNAME ": Found bad scales lonscale=0x%x latscale=0x%x\n", lonscale, latscale); } lon+=lonscale*scarray[buf[jj]>>4]; diff --git a/unicsv.cc b/unicsv.cc index f937e6256..9e9067674 100644 --- a/unicsv.cc +++ b/unicsv.cc @@ -537,7 +537,7 @@ unicsv_fondle_header(QString s) cbuf = buf; } - while ((s = csv_lineparse(cbuf, unicsv_fieldsep, "\"", 0)), !s.isEmpty()) { + while ((s = csv_lineparse(cbuf, unicsv_fieldsep, "\"", 0)), !s.isNull()) { s = s.trimmed(); field_t* f = &fields_def[0]; diff --git a/vecs.cc b/vecs.cc index 4a72d018b..de2e46fe5 100644 --- a/vecs.cc +++ b/vecs.cc @@ -1442,7 +1442,7 @@ alpha(const void* a, const void* b) vecs_t** sort_and_unify_vecs(int* ctp) { - int vc; + size_t vc; vecs_t** svp; #if CSVFMTS_ENABLED #endif @@ -1490,7 +1490,7 @@ sort_and_unify_vecs(int* ctp) } memset(&svp[i]->vec->cap, 0, sizeof(svp[i]->vec->cap)); switch (xcsv_file.datatype) { - case 0: + case unknown_gpsdata: case wptdata: svp[i]->vec->cap[ff_cap_rw_wpt] = (ff_cap)(ff_cap_read | ff_cap_write); break; @@ -1603,7 +1603,7 @@ disp_v2(ff_vecs_t* v) } const char* -name_option(long type) +name_option(uint32_t type) { const char* at[] = { "unknown", diff --git a/waypt.cc b/waypt.cc index 65dfab024..6a705c05c 100644 --- a/waypt.cc +++ b/waypt.cc @@ -19,16 +19,25 @@ */ -#include "defs.h" -#include "cet_util.h" -#include "garmin_fs.h" -#include "grtcirc.h" -#include "session.h" -#include "src/core/logging.h" +#include // for fabs +#include // for printf, fflush, fprintf, stdout +#include // for time_t + +#include // for QByteArray +#include // for QDateTime #include -#include -#include -#include +#include // for QList +#include // for QString, operator== +#include // for QTime +#include // for qPrintable + +#include "defs.h" +#include "garmin_fs.h" // for garmin_ilink_t, garmin_fs_s, GMSD_FIND, garmin_fs_p +#include "grtcirc.h" // for RAD, gcdist, heading_true_degrees, radtometers +#include "queue.h" // for queue, QUEUE_INIT, dequeue, QUEUE_FOR_EACH, QUEUE_MOVE, ENQUEUE_TAIL +#include "session.h" // for curr_session, session_t +#include "src/core/datetime.h" // for DateTime +#include "src/core/logging.h" // for Warning, Fatal #if NEWQ QList waypt_list; @@ -256,11 +265,11 @@ waypt_compute_bounds(bounds* bounds) { waypt_init_bounds(bounds); #if NEWQ - foreach(Waypoint* waypointp, waypt_list) { + foreach (Waypoint* waypointp, waypt_list) { #else queue* elem, *tmp; QUEUE_FOR_EACH(&waypt_head, elem, tmp) { - Waypoint* waypointp = reinterpret_cast(elem); + Waypoint* waypointp = reinterpret_cast(elem); #endif waypt_add_to_bounds(bounds, waypointp); } @@ -270,12 +279,12 @@ Waypoint* find_waypt_by_name(const QString& name) { #if NEWQ - foreach(Waypoint* waypointp, waypt_list) { + foreach (Waypoint* waypointp, waypt_list) { #else queue* elem, *tmp; QUEUE_FOR_EACH(&waypt_head, elem, tmp) { - Waypoint* waypointp = reinterpret_cast(elem); + Waypoint* waypointp = reinterpret_cast(elem); #endif if (waypointp->shortname == name) { return waypointp; @@ -308,7 +317,7 @@ waypt_flush(queue* head) queue* elem, *tmp; QUEUE_FOR_EACH(head, elem, tmp) { - Waypoint* q = reinterpret_cast(dequeue(elem)); + Waypoint* q = reinterpret_cast(dequeue(elem)); delete q; if (head == &waypt_head) { waypt_ct--; @@ -351,7 +360,7 @@ waypt_backup(signed int* count, queue** head_bak) waypt_ct = 0; QUEUE_FOR_EACH(qbackup, elem, tmp) { - wpt = reinterpret_cast(elem); + wpt = reinterpret_cast(elem); waypt_add(new Waypoint(*wpt)); no++; } @@ -536,7 +545,7 @@ waypt_gradient(const Waypoint* A, const Waypoint* B) } double altitude = A->altitude - B->altitude; - if (altitude == 0 || + if (altitude == 0 || A->altitude == unknown_alt || B->altitude == unknown_alt) { return 0; } @@ -646,6 +655,69 @@ Waypoint::Waypoint(const Waypoint& other) : // note: extra_data is not deep copied. } +Waypoint& Waypoint::operator=(const Waypoint& rhs) +{ + if (this != &rhs) { + + // deallocate + if (gc_data != &Waypoint::empty_gc_data) { + delete gc_data; + } + fs_chain_destroy(fs); + + // allocate and copy + // Q(rhs.Q), + latitude = rhs.latitude; + longitude = rhs.longitude; + altitude = rhs.altitude; + geoidheight = rhs.geoidheight; + depth = rhs.depth; + proximity = rhs.proximity; + shortname = rhs.shortname; + description = rhs.description; + notes = rhs.notes; + urls = rhs.urls; + wpt_flags = rhs.wpt_flags; + icon_descr = rhs.icon_descr; + creation_time = rhs.creation_time; + route_priority = rhs.route_priority; + hdop = rhs.hdop; + vdop = rhs.vdop; + pdop = rhs.pdop; + course = rhs.course; + speed = rhs.speed; + fix = rhs.fix; + sat = rhs.sat; + heartrate = rhs.heartrate; + cadence = rhs.cadence; + power = rhs.power; + temperature = rhs.temperature; + odometer_distance = rhs.odometer_distance; + gc_data = rhs.gc_data; + fs = rhs.fs; + session = rhs.session; + extra_data = rhs.extra_data; + // deep copy geocache data unless it is the specail static empty_gc_data. + if (rhs.gc_data != &Waypoint::empty_gc_data) { + gc_data = new geocache_data(*rhs.gc_data); + } + + /* + * It's important that this duplicated waypoint not appear + * on the master Q. + */ + QUEUE_INIT(&Q); + + // deep copy fs chain data. + fs = fs_chain_copy(rhs.fs); + + // note: session is not deep copied. + // note: extra_data is not deep copied. + } + + return *this; +} + bool Waypoint::HasUrlLink() const { diff --git a/xcsv.cc b/xcsv.cc index fba18d3c7..eee9399f5 100644 --- a/xcsv.cc +++ b/xcsv.cc @@ -1465,13 +1465,17 @@ xcsv_waypt_pr(const Waypoint* wpt) /* ALTITUDE CONVERSIONS**********************************************/ case XT_ALT_FEET: /* altitude in feet as a decimal value */ - buff = QString().sprintf(fmp.printfc.constData(), - METERS_TO_FEET(wpt->altitude)); + if (wpt->altitude != unknown_alt) { + buff = QString().sprintf(fmp.printfc.constData(), + METERS_TO_FEET(wpt->altitude)); + } break; case XT_ALT_METERS: /* altitude in meters as a decimal value */ - buff = QString().sprintf(fmp.printfc.constData(), - wpt->altitude); + if (wpt->altitude != unknown_alt) { + buff = QString().sprintf(fmp.printfc.constData(), + wpt->altitude); + } break; /* DISTANCE CONVERSIONS**********************************************/